/*
*	Copyright (c) 2009 Brent Mombourquette
*
*	Permission is hereby granted, free of charge, to any person
*	obtaining a copy of this software and associated documentation
*	files (the "Software"), to deal in the Software without
*	restriction, including without limitation the rights to use,
*	copy, modify, merge, publish, distribute, sublicense, and/or sell
*	copies of the Software, and to permit persons to whom the
*	Software is furnished to do so, subject to the following
*	conditions:
*
*	The above copyright notice and this permission notice shall be
*	included in all copies or substantial portions of the Software.
*
*	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
*	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*	OTHER DEALINGS IN THE SOFTWARE.
*
*	This file contains the functions which control sessions - saving, loading, and starting a new session.
*/
// Import a referrence to the BreadCrumbs database
Components.utils.import("resource://BreadCrumbs/database.jsm");

//Codes for Mozilla's nsIFileOutputStream object init
const MODE_WRITE   = 0x02;
const MODE_CREATE   = 0x08;
const MODE_TRUNCATE = 0x20;
const EXTENSION = ".session";

var sessionControl = {
	/*
	 * Display a filepicker to allow the user to save the session and set up the file stream.
	 */
	saveSession: function() {
		var dirService = Components.classes["@mozilla.org/file/directory_service;1"].
                  getService(Components.interfaces.nsIProperties); 
		var homeDir = dirService.get("Home", Components.interfaces.nsIFile);
	
		var nsIFilePicker = Components.interfaces.nsIFilePicker;
		var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
		fp.init(window, "Save As...", nsIFilePicker.modeSave);	// Create the file picker object, in save mode
		fp.appendFilter("BreadCrumbs Session (*" + EXTENSION + ")", "*" + EXTENSION); // Filter only BreadCrumbs session file type
		fp.defaultExtension = EXTENSION;
		fp.displayDirectory = homeDir; // Shows the home directory by default
		
		var res = fp.show();
		if (res != 1){	//res == nsIFilePicker.returnOk || res == nsIFilePicker.returnReplace would NOT WORK, WHY?
			var file = fp.file;	
			var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
			foStream.init(file, MODE_WRITE | MODE_CREATE | MODE_TRUNCATE, 0666, 0); // Create the file stream, to write, create, and append
			// A precaution, incase we end up dealing with non-ascii characters, which would cause foStream to break
			var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream);
			converter.init(foStream, "UTF-8", 0, 0); // Create the converter to write to the choosen file from the file picker
			sessionControl.writeToFile(converter);
			converter.close();
		}
	},
	
	/*
	 * Write the contents of the database to con.
	 * @param {nsIConverterOutputStream} con
	 */
	writeToFile: function(con) {
		var databaseString = "SELECT * FROM edgeLog;";
		var databaseStatement = breadcrumbsDBConn.createStatement(databaseString);
		
		var row, destination, source, title, ann, fav, image, cords;
		
		try {
			while (databaseStatement.executeStep()){
					row = databaseStatement.getUTF8String(0);
					destination = databaseStatement.getUTF8String(1);
					source = databaseStatement.getUTF8String(2);
					title = databaseStatement.getUTF8String(3);
					ann = databaseStatement.getUTF8String(4);
					fav = databaseStatement.getUTF8String(5);
					permTitle = databaseStatement.getUTF8String(6);
					timeEnter = databaseStatement.getUTF8String(7);
					linkType = databaseStatement.getUTF8String(8);
					image = databaseStatement.getUTF8String(9);
					cords = databaseStatement.getUTF8String(10);
					// Write each entry to the database
					con.writeString(row + "|||" + destination + "|||" + source + "|||" + title + "|||" + ann + "|||" + fav + "|||" + permTitle + "|||" + timeEnter + "|||" + linkType + "|||" + image + "|||" + cords + "|||" + "\n");
			}
		} finally {
			databaseStatement.reset();
			databaseStatement.finalize();
		}
	},
	
	/*
	 * Display a filepicker to allow the user to load a previously saved session and set up the file stream.
	 */
	loadSession: function() {
		var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                        .getService(Components.interfaces.nsIPromptService);
		var choice = prompts.confirm(null, "Load New Session", "Loading a saved session will erase any logged data from your current session. Are you sure you wish to continue?");
		if (!choice) {
			return;
		} else {
			var dirService = Components.classes["@mozilla.org/file/directory_service;1"].
	                  getService(Components.interfaces.nsIProperties); 
			var homeDir = dirService.get("Home", Components.interfaces.nsIFile);
		
			var nsIFilePicker = Components.interfaces.nsIFilePicker;
			var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
			fp.init(window, "Open File..", nsIFilePicker.modeOpen); // Create the file picker object, in open mode
			fp.appendFilter("BreadCrumbs Session (*" + EXTENSION + ")", "*" + EXTENSION); // Filter only BreadCrumbs session file type
			fp.displayDirectory = homeDir; // Shows the home directory by default

			var res = fp.show();
			if (res != 1){	//res == nsIFilePicker.returnOk || res == nsIFilePicker.returnReplace would NOT WORK, WHY?
				var file = fp.file;	
				var data = "";
				var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
				// A precaution, incase we end up dealing with non-ascii characters, which would cause fstream to break
				// var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].createInstance(Components.interfaces.nsIConverterInputStream);
				
				fstream.init(file, -1, 0, 0);
				fstream.QueryInterface(Components.interfaces.nsILineInputStream);
				database.deleteAll(); // Clear the database before loading
				if (window.opener) {
					if (window.opener.on)
						window.opener.util.toggleLogging(); // Make sure it turns off
				}
				
				var line = {}, hasmore;
				var end = new Object();
				
				do {
					hasmore = fstream.readLine(line);
					// Process the file line by line. 
					end = sessionControl.loadToDatabase(line.value);
					// end is only false if the first IF case of loadToDatabase is true, thus meaning there was an error in the file
					if (!end)
						break;
				} while(hasmore);
				
				if (!end) {
					var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                        .getService(Components.interfaces.nsIPromptService);
					prompts.alert(null, "Improper File", "Unable to load file, please try again.");
					database.deleteAll(); // Clean up, incase it was half loaded
					try {
						window.opener.realTimeReload();
					} catch(e) {} // This means the browser window was closed
				} else {
					if (window.opener)
						window.opener.util.resetAfterLoad(end.sor, end.dest); // Loading completed successfully
					try {
						window.opener.realTimeReload();
					} catch(e) {} // This means the browser window was closed
				}
			}
		}
	},
	
	/*
	 * Load the contents of data into the database.
	 * @param {String} data		One entry in the database, with each collumn entry separated by "|||"
	 */
	loadToDatabase: function(data) {
		var fdata = data.replace(/\n/g,'');
		var arr = new Array();
		arr = fdata.split("|||");
		
		// A proper save file will have each of these entries non-null and defined
		if (!(arr[1] && arr[2] && arr[3] && arr[4] && arr[5] && arr[6] && arr[7] && arr[8] && arr[9] && arr[10]))
			return;
		
		var destination, source;
		var insertString = "INSERT INTO edgeLog (row,destination,source,title,annotation,fav,permTitle,timeEnter,linkType,image, cords) VALUES (NULL, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10);";
		var insertStatement = breadcrumbsDBConn.createStatement(insertString);
		
		insertStatement.bindUTF8StringParameter(0, arr[1]);
		insertStatement.bindUTF8StringParameter(1, arr[2]);
		insertStatement.bindUTF8StringParameter(2, arr[3]);
		insertStatement.bindUTF8StringParameter(3, arr[4]);
		insertStatement.bindUTF8StringParameter(4, arr[5]);
		insertStatement.bindUTF8StringParameter(5, arr[6]);
		insertStatement.bindUTF8StringParameter(6, arr[7]);
		insertStatement.bindInt32Parameter(7, arr[8]);
		insertStatement.bindUTF8StringParameter(8, arr[9]);
		insertStatement.bindUTF8StringParameter(9, arr[10]);
			
		// The following two variables are used so that upon the final iteration they 
		// contain the information of where the user left off in the newly loaded session
		destination = arr[1];
		source = arr[2];
			
		try {
			while(insertStatement.executeStep()){
			}
		} finally {
			insertStatement.reset();
			insertStatement.finalize();
		}
			
		return {dest: destination, sor: source};	
	},
	
	/*
	 * Begin a new logging session.
	 * Globals: first [from log.js], on [from log.js], realTimeReload() [from util.js]
	 */
	newSession: function() {
		var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                        .getService(Components.interfaces.nsIPromptService);
		var choice = prompts.confirm(null, "Start New Session", "Starting a new session will erase any logged data from your current session. Are you sure you wish to continue?");
		if (!choice) {
			return;
		} else {
			first = true;
			if (on)
				util.toggleLogging();
			util.deleteAll();
			try {
				realTimeReload(); // This is only ever called from the browser overlay so we dont need to use window.opener
			} catch(e) {
				// This means graph_page.html is not open
			}
		}
	}
}